{ "cells": [ { "cell_type": "markdown", "id": "0f02ba3e", "metadata": {}, "source": [ "(plotmon-tutorial)=\n", "# Tutorial 5. Plot monitor\n", "\n", "```{seealso}\n", "The complete source code of this tutorial can be found in\n", "\n", "{nb-download}`Tutorial 5. Plot monitor.ipynb`\n", "```\n", "\n", "In this tutorial we dive into the capabilities of the plot monitor.\n", "We will create a fictional device and showcase how the plot monitor can be used. Enjoy!" ] }, { "cell_type": "code", "execution_count": null, "id": "6484ae50", "metadata": { "mystnb": { "code_prompt_show": "Imports and auxiliary utilities" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "import numpy as np\n", "from IPython.core.interactiveshell import InteractiveShell\n", "from qcodes import Instrument, ManualParameter\n", "\n", "from quantify_core.data.handling import (\n", " get_tuids_containing,\n", " set_datadir,\n", " default_datadir,\n", ")\n", "from quantify_core.measurement import MeasurementControl\n", "from quantify_core.visualization.pyqt_plotmon import PlotMonitor_pyqt\n", "\n", "rng = np.random.default_rng(seed=555555) # random number generator\n", "\n", "# Display any variable or statement on its own line\n", "InteractiveShell.ast_node_interactivity = \"all\"" ] }, { "cell_type": "markdown", "id": "fc61ac08", "metadata": {}, "source": [ "Before instantiating any instruments or starting a measurement we change the\n", "directory in which the experiments are saved using the\n", "{meth}`~quantify_core.data.handling.set_datadir`\n", "\\[{meth}`~quantify_core.data.handling.get_datadir`\\] functions.\n", "\n", "----------------------------------------------------------------------------------------\n", "\n", "⚠️ **Warning!**\n", "\n", "We recommend always setting the directory at the start of the python kernel and stick\n", "to a single common data directory for all notebooks/experiments within your\n", "measurement setup/PC.\n", "\n", "The cell below sets a default data directory (`~/quantify-data` on Linux/macOS or\n", "`$env:USERPROFILE\\\\quantify-data` on Windows) for tutorial purposes. Change it to your\n", "desired data directory. The utilities to find/search/extract data only work if\n", "all the experiment containers are located within the same directory.\n", "\n", "----------------------------------------------------------------------------------------" ] }, { "cell_type": "code", "execution_count": null, "id": "4917d7c0", "metadata": {}, "outputs": [], "source": [ "set_datadir(default_datadir())" ] }, { "cell_type": "markdown", "id": "1a3f17ca", "metadata": {}, "source": [ "## QCoDeS drivers for our instruments" ] }, { "cell_type": "code", "execution_count": null, "id": "349ab1d1", "metadata": {}, "outputs": [], "source": [ "class Device(Instrument):\n", " \"\"\"A dummy instrument.\"\"\"\n", "\n", " def __init__(self, name: str):\n", " super().__init__(name=name)\n", "\n", " self.add_parameter(name=\"amp_0\", unit=\"A\", parameter_class=ManualParameter)\n", " self.add_parameter(name=\"amp_1\", unit=\"A\", parameter_class=ManualParameter)\n", " self.add_parameter(name=\"offset\", unit=\"A\", parameter_class=ManualParameter)\n", "\n", " self.add_parameter(\n", " name=\"adc\", label=\"ADC input\", unit=\"V\", get_cmd=self._get_dac_value\n", " )\n", "\n", " def _get_dac_value(self):\n", " s1 = np.exp(-3 * self.amp_0()) * np.sin(self.amp_0() * 2 * np.pi * 3)\n", " s2 = np.cos(self.amp_1() * 2 * np.pi * 2)\n", " return s1 + s2 + rng.uniform(0, 0.2) + self.offset()" ] }, { "cell_type": "markdown", "id": "56e3db7c", "metadata": {}, "source": [ "## Instantiate the instruments" ] }, { "cell_type": "code", "execution_count": null, "id": "07c2c898", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "meas_ctrl = MeasurementControl(\"meas_ctrl\")\n", "plotmon = PlotMonitor_pyqt(\"PlotMonitor\")\n", "meas_ctrl.instr_plotmon(plotmon.name)\n", "device = Device(\"Device\")" ] }, { "cell_type": "markdown", "id": "7802d401", "metadata": {}, "source": [ "## Overview\n", "\n", "There are 3 parameters in the {class}`.PlotMonitor_pyqt` that control the datasets being displayed.\n", "\n", "Two main parameters determine the datasets being displayed: *tuids* and *tuids_extra*." ] }, { "cell_type": "code", "execution_count": null, "id": "cd613555", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "plotmon.tuids()\n", "plotmon.tuids_extra()" ] }, { "cell_type": "markdown", "id": "826bc696", "metadata": {}, "source": [ "The interface is the same for both. The parameters accept a list of tuids or an empty list to reset." ] }, { "cell_type": "code", "execution_count": null, "id": "07eff7cf", "metadata": {}, "outputs": [], "source": [ "### Example of loading datasets onto the plot\n", "#plotmon.tuids([\"20201124-184709-137-8a5112\", \"20201124-184716-237-918bee\"])\n", "#plotmon.tuids_extra([\"20201124-184722-988-0463d4\", \"20201124-184729-618-85970f\"])" ] }, { "cell_type": "markdown", "id": "ce8f99ee", "metadata": {}, "source": [ "The difference is that the {class}`.MeasurementControl` uses `tuids` and overrides them when running measurements.\n", "\n", "```{note}\n", "All the datasets must have matching data variables (settables and gettables).\n", "```\n", "\n", "The third relevant parameter is the `tuids_max_num`. It accepts an integer that determines the maximum number of datasets that will be stored in `tuids` when the {class}`.MeasurementControl` is running." ] }, { "cell_type": "code", "execution_count": null, "id": "869ddca3", "metadata": {}, "outputs": [], "source": [ "plotmon.tuids_max_num()" ] }, { "cell_type": "markdown", "id": "51aa0293", "metadata": {}, "source": [ "```{note}\n", "This parameter has no effect when setting the `tuids` manually.\n", "```\n", "\n", "## Usage examples" ] }, { "cell_type": "code", "execution_count": null, "id": "129d0923", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "# set initial values to emulate the instrument state\n", "device.amp_0(0.0)\n", "device.amp_1(0.0)\n", "device.offset(0.0)\n", "\n", "n_pnts = 50\n", "\n", "meas_ctrl.settables(device.amp_0)\n", "meas_ctrl.setpoints(np.linspace(0, 1, n_pnts))\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan\")" ] }, { "cell_type": "code", "execution_count": null, "id": "f15ebbd4", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot" ] }, { "cell_type": "code", "execution_count": null, "id": "94ddd682", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "n_pnts = 20\n", "\n", "meas_ctrl.settables(device.amp_0)\n", "meas_ctrl.setpoints(np.linspace(0, 1, n_pnts))\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan\")" ] }, { "cell_type": "code", "execution_count": null, "id": "c667bfb9", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot" ] }, { "cell_type": "code", "execution_count": null, "id": "fe9bcc5f", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "n_pnts = 30\n", "\n", "meas_ctrl.settables(device.amp_0)\n", "meas_ctrl.setpoints(np.linspace(0, 1, n_pnts))\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan\")" ] }, { "cell_type": "code", "execution_count": null, "id": "17ac220c", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot" ] }, { "cell_type": "markdown", "id": "d6d8ab82", "metadata": {}, "source": [ "Now the oldest dataset will vanish from the plot:" ] }, { "cell_type": "code", "execution_count": null, "id": "ac84a3ab", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "# Now the oldest dataset will vanish from the plot\n", "\n", "n_pnts = 40\n", "\n", "meas_ctrl.settables(device.amp_0)\n", "meas_ctrl.setpoints(np.linspace(0, 1, n_pnts))\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan\")" ] }, { "cell_type": "code", "execution_count": null, "id": "851cdc2b", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot" ] }, { "cell_type": "markdown", "id": "1e58a13a", "metadata": {}, "source": [ "We can accumulate more datasets on the plot if we want to:" ] }, { "cell_type": "code", "execution_count": null, "id": "20bd0f42", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "# We can accumulate more datasets on the plot if we want to\n", "plotmon.tuids_max_num(4)\n", "n_pnts = 40\n", "\n", "meas_ctrl.settables(device.amp_0)\n", "meas_ctrl.setpoints(np.linspace(0, 1, n_pnts))\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan\")" ] }, { "cell_type": "code", "execution_count": null, "id": "9d466e93", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot" ] }, { "cell_type": "markdown", "id": "080175cd", "metadata": {}, "source": [ "Or we can disable the accumulation and plot a single dataset:" ] }, { "cell_type": "code", "execution_count": null, "id": "67a9a1eb", "metadata": {}, "outputs": [], "source": [ "# Or we can disable the accumulation and plot a single dataset\n", "plotmon.tuids_max_num(1)\n", "\n", "plotmon.main_QtPlot" ] }, { "cell_type": "markdown", "id": "728eac9b", "metadata": {}, "source": [ "This can also be reset:" ] }, { "cell_type": "code", "execution_count": null, "id": "c6cc5a28", "metadata": {}, "outputs": [], "source": [ "# This can also be reset with\n", "plotmon.tuids([])\n", "\n", "plotmon.main_QtPlot # The plotting window will vanish, it is supposed to" ] }, { "cell_type": "markdown", "id": "535363cf", "metadata": {}, "source": [ "For now, we will allow two datasets on the plot monitor." ] }, { "cell_type": "code", "execution_count": null, "id": "ce2c3c71", "metadata": {}, "outputs": [], "source": [ "# For now we will allow two datasets on the plot monitor\n", "plotmon.tuids_max_num(2)" ] }, { "cell_type": "markdown", "id": "7dd508f1", "metadata": {}, "source": [ "Now let's imagine that something strange is happening with our setup..." ] }, { "cell_type": "code", "execution_count": null, "id": "385f2c91", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "# Now let's imagine that something strange is happening with our setup\n", "device.offset(1.5)\n", "\n", "n_pnts = 40\n", "meas_ctrl.settables(device.amp_0)\n", "meas_ctrl.setpoints(np.linspace(0, 1, n_pnts))\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan problem\")" ] }, { "cell_type": "code", "execution_count": null, "id": "ba7667b8", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot" ] }, { "cell_type": "markdown", "id": "efc5350a", "metadata": {}, "source": [ "We would like to compare if the current behavior matches for example what we got a few minutes ago:" ] }, { "cell_type": "code", "execution_count": null, "id": "d731a726", "metadata": {}, "outputs": [], "source": [ "# We would like to compare if the current behavior matches for example\n", "# what we got a few minutes ago\n", "\n", "reference_tuids = sorted(get_tuids_containing(\"ADC\"))[-3:-1]\n", "\n", "plotmon.tuids_extra(reference_tuids)\n", "plotmon.main_QtPlot" ] }, { "cell_type": "markdown", "id": "d173de36", "metadata": {}, "source": [ "OK... that cable was not connected in the right place..." ] }, { "cell_type": "code", "execution_count": null, "id": "bef00343", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "device.offset(0.0) # OK... that cable was not connected in the right place...\n", "\n", "# Now let's run again our experiments while we compare it to the previous one in realtime\n", "\n", "n_pnts = 30\n", "meas_ctrl.settables(device.amp_0)\n", "meas_ctrl.setpoints(np.linspace(0, 1, n_pnts))\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan\")\n", "\n", "n_pnts = 40\n", "meas_ctrl.settables(device.amp_0)\n", "meas_ctrl.setpoints(np.linspace(0, 1, n_pnts))\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan\")" ] }, { "cell_type": "code", "execution_count": null, "id": "9487a865", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot" ] }, { "cell_type": "markdown", "id": "a5df23be", "metadata": {}, "source": [ "We do not need the reference datasets anymore" ] }, { "cell_type": "code", "execution_count": null, "id": "06bd47d4", "metadata": {}, "outputs": [], "source": [ "# We do not need the reference datasets anymore\n", "plotmon.tuids_extra([])\n", "plotmon.main_QtPlot" ] }, { "cell_type": "code", "execution_count": null, "id": "fd607141", "metadata": {}, "outputs": [], "source": [ "# Note: both plotmon.tuids_extra and plotmon.tuids can be used\n", "# but keep in mind that meas_ctrl also uses the plotmon.tuids\n", "\n", "tuids = get_tuids_containing(\"problem\")[0:1]\n", "tuids\n", "plotmon.tuids(tuids)\n", "\n", "n_pnts = 40\n", "meas_ctrl.settables(device.amp_0)\n", "meas_ctrl.setpoints(np.linspace(0, 1, n_pnts))\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan\")\n", "\n", "plotmon.main_QtPlot" ] }, { "cell_type": "markdown", "id": "ddbafd26", "metadata": {}, "source": [ "When we have 2D plots only the first dataset from `plotmon.tuids` or `plotmon.tuids_extra` will be plotted in the secondary window, in that order of priority." ] }, { "cell_type": "code", "execution_count": null, "id": "280ed404", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "# When we have 2D plots only the first dataset from plotmon.tuids or\n", "# plotmon.tuids_extra, in that order of priority, will be plotted in the\n", "# secondary window\n", "\n", "meas_ctrl.settables([device.amp_0, device.amp_1])\n", "meas_ctrl.setpoints_grid([np.linspace(0, 1, 20), np.linspace(0, 0.5, 15)])\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan 2D\")\n", "reference_tuid_2D = dset.attrs[\"tuid\"]" ] }, { "cell_type": "code", "execution_count": null, "id": "feeec88e", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot\n", "plotmon.secondary_QtPlot" ] }, { "cell_type": "markdown", "id": "bfedda46", "metadata": {}, "source": [ "```{note}\n", "The secondary window displays the last dataset with a 2D structure, and it remains persistent until replaced by a new dataset with a 2D structure.\n", "\n", "Mind that the data on the secondary window does not always display data corresponding to the same dataset as the main window.\n", "```\n", "\n", "We still have the persistence of the previous dataset on the main window:" ] }, { "cell_type": "code", "execution_count": null, "id": "d4537bdc", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "meas_ctrl.settables([device.amp_0, device.amp_1])\n", "meas_ctrl.setpoints_grid([np.linspace(0, 1, 20), np.linspace(0, 0.5, 15)])\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan 2D\")" ] }, { "cell_type": "code", "execution_count": null, "id": "6fd9c8d4", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot\n", "plotmon.secondary_QtPlot" ] }, { "cell_type": "markdown", "id": "862504b9", "metadata": {}, "source": [ "We can still have a permanent dataset as a reference in the main window:" ] }, { "cell_type": "code", "execution_count": null, "id": "9cfc10fe", "metadata": { "mystnb": { "remove-output": true } }, "outputs": [], "source": [ "device.offset(2.03)\n", "plotmon.tuids_extra([reference_tuid_2D])\n", "\n", "meas_ctrl.settables([device.amp_0, device.amp_1])\n", "meas_ctrl.setpoints_grid([np.linspace(0, 1, 20), np.linspace(0, 0.5, 15)])\n", "meas_ctrl.gettables(device.adc)\n", "dset = meas_ctrl.run(\"ADC scan 2D\")" ] }, { "cell_type": "code", "execution_count": null, "id": "97fd924a", "metadata": {}, "outputs": [], "source": [ "plotmon.main_QtPlot\n", "plotmon.secondary_QtPlot" ] }, { "cell_type": "markdown", "id": "b8762658", "metadata": {}, "source": [ "But if we want to see the 2D plot we need to reset `plotmon.tuids`." ] }, { "cell_type": "code", "execution_count": null, "id": "6895985e", "metadata": {}, "outputs": [], "source": [ "plotmon.tuids([])\n", "plotmon.tuids_extra([reference_tuid_2D])\n", "plotmon.main_QtPlot\n", "plotmon.secondary_QtPlot" ] }, { "cell_type": "code", "execution_count": null, "id": "215bcf9b", "metadata": {}, "outputs": [], "source": [ "plotmon.tuids()" ] }, { "cell_type": "markdown", "id": "ca421487", "metadata": {}, "source": [ "Now your life will never be the same again ;)" ] } ], "metadata": { "file_format": "mystnb", "jupytext": { "text_representation": { "extension": ".md", "format_name": "myst" } }, "kernelspec": { "display_name": "python3", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 5 }